package cn.uncode.springcloud.gateway.handler;


import java.util.Map;

import cn.uncode.springcloud.gateway.ribbon.RibbonContextHolder;
import cn.uncode.springcloud.utils.obj.ObjectUtil;
import cn.uncode.springcloud.utils.string.StringUtil;
import com.netflix.loadbalancer.AbstractServerPredicate;
import com.netflix.loadbalancer.PredicateKey;
import com.netflix.loadbalancer.ZoneAvoidanceRule;
import com.netflix.niws.loadbalancer.DiscoveryEnabledServer;

import lombok.extern.slf4j.Slf4j;

/**
 * <p>
 * 路由微服务断言
 * <p>
 * 1. eureka metadata 存在版本定义时候进行判断
 * 2. 不存在 metadata 直接返回true
 * 
 * @author juny
 * @date 2019年1月24日
 *
 */
@Slf4j
public class RibbonCanaryRuleHandler extends ZoneAvoidanceRule {
	
	/**
	 * 应用版本
	 */
	public static final String APP_VERSION_EUREKA_METADATA_KEY = "canaryFlag";

    @Override
    public AbstractServerPredicate getPredicate() {
        return new AbstractServerPredicate() {
            @Override
            public boolean apply(PredicateKey predicateKey) {
            	//1、查看目标选择节点状态，是正常节点，还是灰度节点
            	String canaryFlag = null;
            	boolean canary = false;
            	DiscoveryEnabledServer server = (DiscoveryEnabledServer) predicateKey.getServer();
            	final Map<String, String> metadata = server.getInstanceInfo().getMetadata();
            	if(null != metadata && metadata.size() > 0) {
            		canaryFlag = metadata.get(APP_VERSION_EUREKA_METADATA_KEY);
            	}
            	if(StringUtil.isNotBlank(canaryFlag)) {
            		canary = true;
            		log.info("该节点为灰度节点："+server.toString() + ", canaryFlag:" + canaryFlag);
            	}else {
            		log.info("该节点为正常节点："+server.toString());
            	}
            	//2、正常节点
            	if(!canary) {
                	//2.1、请求上下文变量为空，视为正常请求
                    if (ObjectUtil.isEmpty(RibbonContextHolder.getCurrentContext())) {
                        log.info("请求上下文中无灰度信息");
                        return true;
                    }else {
                    	//2.2、请求上下文变量不为空，灰度服务列表中没有目标调用服务名称，说明只有正常节点
                        if(!RibbonContextHolder.getCurrentContext().containsCanaryAppName(server.getInstanceInfo().getAppName())) {
                            return true;
                        }else {//2.3、目标调用服务名称在灰度服务列表中，但目标调用节点是正常节点，需要重新选择
                        	return false;
                        }
                    }
                   
            	}else {//3、灰度节点
            		//3.1、请求上下文变量为空，视为正常请求
            		if (ObjectUtil.isEmpty(RibbonContextHolder.getCurrentContext())) {
                        log.info("请求上下文中无灰度信息");
                        //正常请求到了灰度节点，重新选择节点
                        return false;
                    }else {
                    	//3.2、灰度请求，灰度节点，判断标识是否匹配
                		boolean match = RibbonContextHolder.getCurrentContext().getCanaryFlag().equals(canaryFlag);
                		//匹配成功
                		if(match) {
                			if (match) {
                            	log.warn("当前请求微灰度标识为：{}，目标调用服务名：{}， 匹配成功节点：{}", RibbonContextHolder.getCurrentContext().getCanaryFlag(), 
                            			server.getInstanceInfo().getAppName(), server.getInstanceInfo().getIPAddr()+":"+server.getInstanceInfo().getPort());
                            }
                			return true;
                		}else {
                            return false;
                		}
                    }
            		
            	}
            }
        };
    }
    
    /**
     * 匹配
     * @param target 目标
     * @param versionPhase 版本阶段
     * @return RibbonContext
     */
	private boolean versionMatch(String target, String versionPhase) {
		if (StringUtil.isBlank(target) || StringUtil.isBlank(versionPhase)) {
			return false;
		}
		int index = target.lastIndexOf(versionPhase);
		int length = target.length() - versionPhase.length();
		return index == length;
	}
}
